﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Imaging;

namespace SteganographyDemo
{
	public partial class Form1 : Form
	{
		private Bitmap inputImage;
		private Bitmap outputImage;
		private string inputText;
		private string fileName;

		public Form1()
		{
			InitializeComponent();
		}

		private void newToolStripMenuItem_Click(object sender, EventArgs e)
		{
			inputImage = new Bitmap(pictureBox1.Width, pictureBox1.Height);
			outputImage = inputImage;
			pictureBox1.Image = inputImage;
			pictureBox2.Image = inputImage;
			fileName = null;
			inputText = null;
			richTextBox1.Text = "";
			richTextBox2.Text = "";
		}

		private void openImageToolStripMenuItem_Click(object sender, EventArgs e)
		{
            openFileDialog1.Filter = "BMP (*.bmp)|*.bmp;" +
                "|JPG (*.jpg, *.jpeg)|*.jpg;*.jpeg;|PNG (*.png)|*.png;";
			DialogResult dr = openFileDialog1.ShowDialog();
			if (dr == DialogResult.OK)
			{
				inputImage = new Bitmap(openFileDialog1.FileName);
				pictureBox1.Image = inputImage;
			}
		}

		private void saveToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (fileName == null)
			{
				saveAsToolStripMenuItem_Click(sender, e);
			}
			else
			{
				inputImage.Save(fileName);
			}
		}

		private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			DialogResult dr = saveFileDialog1.ShowDialog();
			if (dr == DialogResult.OK)
			{
				fileName = saveFileDialog1.FileName;
				outputImage.Save(fileName + ".bmp", ImageFormat.Bmp);
			}
		}

		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			Close();
		}

        private string DecimalToBinary(int number)
        {
            int binaryHolder;
            char[] binaryArray;
            string binaryResult = "";
            string finalResult = "";

            while (number > 0)
            {
                binaryHolder = number % 2;
                binaryResult += binaryHolder;
                number = number / 2;
            }

            binaryArray = binaryResult.ToCharArray();

            for (int i = binaryArray.Length - 1; i >= 0; i--)
            {
                finalResult += binaryArray[i];
            }

            while (finalResult.Length < 8)
            {
                finalResult = "0" + finalResult;
            }

            return finalResult;
        }

        private int BinaryToDecimal(string number)
        {
            int output = Convert.ToInt32(number, 2);
            return output;
        }

        private int TextToDecimal(string inputString)
        {
            byte[] decimalArray = new byte[inputString.Length];
            for (int i = 0; i < inputString.Length; i++)
            {
                char tempChar = inputString[i];
                byte decChar = Convert.ToByte(tempChar);
                decimalArray[i] = decChar;
            }
            int output = BitConverter.ToInt32(decimalArray, 0);
            return output;
        }

        private string CharToBinary(char inputChar)
        {
            int converted = Convert.ToInt32(inputChar);
            string output = DecimalToBinary(converted);

            while (output.Length < 8)
            {
                output = "0" + output;
            }

            return output;
        }

        private char BinaryToChar(string input)
        {
            int converted = BinaryToDecimal(input);
            return Convert.ToChar(converted);
        }

        private string[] TextToBinary(string inputString)
        {
            string[] binaryArray = new string[inputString.Length];
            for (int i = 0; i < inputString.Length; i++)
            {
                binaryArray[i] = CharToBinary(inputString[i]);
            }
            return binaryArray;
        }

        private string ReplaceEnd(string inputString, char endNumber)
        {
            string outputString = "";
            for (int i = 0; i < inputString.Length - 1; i++)
            {
                outputString += inputString[i];
            }
            return outputString += endNumber;
        }

        // Takes byte data for three pixels.
        private byte[] CharToColor(byte[] inputColors, char inputChar)
        {
            byte[] outputColors = new byte[inputColors.Length];
            string[] intermediates = new string[inputColors.Length];
            byte[] temp = new byte[inputColors.Length];
            for (int i = 0; i < inputColors.Length; i++)
            {
                intermediates[i] = DecimalToBinary(inputColors[i]);
            }

            string charBinary = CharToBinary(inputChar);
            for (int i = 0; i < charBinary.Length; i++)
            {
                intermediates[i] = ReplaceEnd(intermediates[i], charBinary[i]);
                outputColors[i] = (byte)BinaryToDecimal(intermediates[i]);
                temp[i] = (byte)TextToDecimal(intermediates[i]);
            }
            return outputColors;
        }

        private string GetEnd(string inputString)
        {
            string end = Convert.ToString(inputString[inputString.Length - 1]);
            return end;
        }

        private char ColorToChar(byte[] inputColors)
        {
            string[] intermediates = new string[inputColors.Length];
            char[] endValues = new char[8];
            string temp = "";
            
            for (int i = 0; i < inputColors.Length; i++)
            {
                intermediates[i] = DecimalToBinary(inputColors[i]);
                endValues[i] = Convert.ToChar(GetEnd(intermediates[i]));
                temp += endValues[i];
            }
            return BinaryToChar(temp);
        }

        private void Encode(Bitmap inputImage, string inputString)
        {
            BitmapData tempImage = inputImage.LockBits(
                new Rectangle(0, 0, inputImage.Width, inputImage.Height),
                ImageLockMode.ReadWrite,
                inputImage.PixelFormat);
            int size = tempImage.Stride * tempImage.Height;
            byte[] data = new byte[size];

            System.Runtime.InteropServices.Marshal.Copy(tempImage.Scan0, data, 0, size);

            int sum = 0;
            for (int y = 0; y < tempImage.Height; y++)
            {
                for (int x = 0; x < tempImage.Stride - 7; x += 8)
                {
                    if (sum < inputString.Length)
                    {
                        int pos = y * tempImage.Stride + x;
                        byte[] colorTrio = new byte[8];
                        for (int i = 0; i < colorTrio.Length; i++)
                        {
                            colorTrio[i] = data[pos + i];
                        }

                        colorTrio = CharToColor(colorTrio, inputString[sum]);

                        for (int i = 0; i < colorTrio.Length; i++)
                        {
                            data[pos + i] = colorTrio[i];
                        }
                    }
                    sum++;
                }
            }

            System.Runtime.InteropServices.Marshal.Copy(data, 0, tempImage.Scan0, data.Length);
            inputImage.UnlockBits(tempImage);
        }

        private void Decode(Bitmap inputImage)
        {
            BitmapData tempImage = inputImage.LockBits(
                new Rectangle(0, 0, inputImage.Width, inputImage.Height),
                ImageLockMode.ReadWrite,
                inputImage.PixelFormat);
            int size = tempImage.Stride * tempImage.Height;
            byte[] data = new byte[size];
            string message = "";

            System.Runtime.InteropServices.Marshal.Copy(tempImage.Scan0, data, 0, size);

            int sum = 0;
            for (int y = 0; y < tempImage.Height; y++)
            {
                for (int x = 0; x < tempImage.Stride - 7; x += 8)
                {
                    if (sum < 1000)
                    {
                        int pos = y * tempImage.Height + x;
                        byte[] colorTrio = new byte[8] {
                               data[pos], data[pos+1], data[pos+2],
                                data[pos+3], data[pos+4], data[pos+5],
                                data[pos+6], data[pos+7] };
                        char tempChar = ColorToChar(colorTrio);
                        message += tempChar;
                    }
                    sum++;
                }
            }
            
            System.Runtime.InteropServices.Marshal.Copy(data, 0, tempImage.Scan0, data.Length);
            inputImage.UnlockBits(tempImage);
            richTextBox2.Text = message;
        }

		private void encodeButton_Click(object sender, EventArgs e)
		{
            if (pictureBox1.Image == null)
            {
                MessageBox.Show("An image needs to be opened first.");
                openImageToolStripMenuItem_Click(sender, e);
                return;
            }

            if (richTextBox1.Text == "")
            {
                MessageBox.Show("A message needs to be entered first.");
                return;
            }
            else
            {
                inputText = richTextBox1.Text;
                Encode(inputImage, inputText);
                pictureBox2.Image = inputImage;
                outputImage = inputImage;
            }
		}

		private void decodeButton_Click(object sender, EventArgs e)
		{
			Bitmap toDecode;

            if (pictureBox1.Image == null)
            {
                MessageBox.Show("An image needs to be opened first.");
                openImageToolStripMenuItem_Click(sender, e);
                pictureBox2.Image = pictureBox1.Image;
                return;
            }
            else
            {
                toDecode = (Bitmap)pictureBox1.Image;
                Decode(toDecode);
            }
		}
	}
}
